package com.whty.ws_fengx.webSocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @Auther: morou
 * @Description: websocket的具体实现类
 * 使用springboot的唯一区别是要@Component声明下，而使用独立容器是由容器自己管理websocket的，
 * 但在springboot中连容器都是spring管理的。
虽然@Component默认是单例模式的，但springboot还是会为每个websocket连接初始化一个bean，
所以可以用一个静态set保存起来。
 */
@Slf4j
@ServerEndpoint(value = "/websocket/{userId}")
@Component
public class MyWebSocket {
    //用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
    //将userId与session绑定
    private static Map<Long, Session> sessionMap = new HashMap<>();
    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;
    //存储当前用户名
    private Long userId;

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Long userId) {
        this.session = session;
        this.userId = userId;
        webSocketSet.add(this);     //加入set中
        sessionMap.put(userId, session);
        log.info("有新连接加入！当前在线人数为" + webSocketSet.size());
        this.session.getAsyncRemote().sendText("恭喜您成功连接上FengX-->当前在线人数为："+ webSocketSet.size());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        log.info("有一连接关闭！当前在线人数为" + webSocketSet.size());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, @PathParam("userId")Long userId, Session session) {
        log.info("来自用户" + userId + "的消息:" + message);
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            SocketMsg socketMsg = objectMapper.readValue(message, SocketMsg.class);
            socketMsg.setFromUser(userId);
            String msg = socketMsg.getMsg();
            Session fromSession = session;

            //根据用户ID私聊发送消息
            if (socketMsg.getType() == 1){
                Long toUser = socketMsg.getToUser();
                Session toSession = sessionMap.get(toUser);
                //如果接收方在线
                if (toSession != null){
                    sendMsg(fromSession, userId, msg);
                    sendMsg(toSession, userId, msg);
                }else{
                    //如果接收方不在线
                    msg = "接收方不在线,稍后联系";
                    sendMsg(fromSession, userId, msg);
                }
            }else{
                //广播发送消息
                broadcastMsg(userId,msg);
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发生错误时调用
     *
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 群发自定义消息
     * */
    public void broadcastMsg(Long userId, String message){
        for (MyWebSocket item : webSocketSet) {
            sendMsg(item.session, userId, message);
        }
    }


    public void sendMsg(Session session, Long userId, String message){
        session.getAsyncRemote().sendText(userId + ":" + message);

    }
}